package com.cskaoyan.javase.recursion._0introduction;

/**
 * @description: 递归的引入
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 回到Java语法当中，方法是可以调用方法的。
 * > ​	实际上，我们总是在main方法（程序入口方法）中调用其它方法，才能够去使用该方法
 * - 特别的，在一个方法当中再次调用这个方法，就像故事里提到同样的故事一样
 * - 我们把方法在运行时调用自身的情况，称之为递归，又叫做递归调用
 *
 * 方法的递归的使用注意事项：
 *      1，递归调用方法时，必须指出递归结束的条件，如果“只递不归”会出现栈溢出错误。
 *          这种递归结束的条件称之为递归的出口
 *      2，递归有了出口也不是一定不会出错的，如果递归的出口过于“遥远”，仍然会导致递归出错，栈溢出
 *          这种情况我们称之为“递归的深度”超过了界限
 *      3，递归的使用风险很高，栈溢出错误一旦发生对程序是致命错误
 *
 */
public class Demo {
    public static void main(String[] args) {

        System.out.println(sum(100));
        /**
         * 分析一下上述方法:
         * sum(10) = 10 + sum(9)
         * sum(9) = 9 + sum(8)
         * sum(8) = 8 + sum(7)
         * ....
         * 显然上述过程是不可能停下来的,会一直进行下去
         * 请思考程序会出现什么情况:
         * 1,死循环
         * 2,程序出错终止
         * 3,电脑炸了
         *
         * 通过运行代码我们发现程序报错终止,并抛出异常StackOverflowError
         * StackOverflowError: 栈溢出错误,它属于Error级别的异常,是一个严重的错误
         * 栈指的是JVM栈,JVM溢出报错了
         * Method 'sum()' recurses infinitely, and can only end by throwing an exception
         *
         * 错误的原因是方法栈帧只进不出，所以解决方案是让方法的栈帧能够出来，换句话说让方法调用自身的过程能够终止
         *
         * 加一个条件再分析一下程序：
         * if (n == 0){
         *             return 0;
         * }
         * sum(10) = 10 + sum(9);
         * ...
         * sum(1) = 1 + sum(0);
         * sum(0) = 0;
         * 以上结果是 10 + 9 + 8 +...+1
         *
         */
    }

    //简单的递归调用
    public static int sum(int n) {
        //加一个条件终止方法的递归调用
        if (n == 0){
            return 0;
        }
        return n + sum(n - 1);
    }
}
